﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using XMouseMSTM;

namespace XMouseMSTM
{
    class WinAPI
    {
        //Loading DLL's for interop commands

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(int hWnd, uint Msg, uint wParam, uint lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);

        [DllImport("user32.dll", EntryPoint = "keybd_event", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern void keybd_event(byte vk, byte scan, int flags, int extrainfo);

        [DllImport("user32.dll")]
        static extern int GetForegroundWindow();

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowPlacement(int hWnd, ref WINDOWPLACEMENT lpwndpl);

        // [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        // public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(String sClassName, String sAppName);

        // Essential structures for DLL operations

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left, top, right, bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator System.Drawing.Point(POINT p)
            {
                return new System.Drawing.Point(p.X, p.Y);
            }

            public static implicit operator POINT(System.Drawing.Point p)
            {
                return new POINT(p.X, p.Y);
            }
        }



        [Serializable]
        [StructLayout(LayoutKind.Sequential)]
        internal struct WINDOWPLACEMENT
        {
            /// <summary>
            /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT).
            /// <para>
            /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly.
            /// </para>
            /// </summary>
            public int Length;

            /// <summary>
            /// Specifies flags that control the position of the minimized window and the method by which the window is restored.
            /// </summary>
            public int Flags;

            /// <summary>
            /// The current show state of the window.
            /// </summary>
            public int ShowCmd;

            /// <summary>
            /// The coordinates of the window's upper-left corner when the window is minimized.
            /// </summary>
            public POINT MinPosition;

            /// <summary>
            /// The coordinates of the window's upper-left corner when the window is maximized.
            /// </summary>
            public POINT MaxPosition;

            /// <summary>
            /// The window's coordinates when the window is in the restored position.
            /// </summary>
            public RECT NormalPosition;

            /// <summary>
            /// Gets the default (empty) value.
            /// </summary>
            public static WINDOWPLACEMENT Default
            {
                get
                {
                    WINDOWPLACEMENT result = new WINDOWPLACEMENT();
                    result.Length = Marshal.SizeOf(result);
                    return result;
                }
            }
        }

        // flags for storing Window Handle that has just been minimized
        // because it will lose GetForeGroundWindow() handle since it will minimize.

        public static int last_hwnd = 0;
        public static int acceptable_hwnd = 0;
        public static IntPtr startbuttonHandle = FindWindow("Button", "Start"); // I noticed that after all visible windows are minimized , GetForeGroungWindow() then always returns the Start Button Handle 


        //Main function to Minimize/Maximize/Restore windows
        //direction comes from function that analyzes if touch has downward or upward direction


        public static void GetPlacement(int direction)
        {

            WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
            placement.Length = Marshal.SizeOf(placement);
            GetWindowPlacement(GetForegroundWindow(), ref placement);



            if (direction == 1) // if direction is upward
            {
                if (last_hwnd != 0) // a check and flag intializing when window was already minimized
                {
                    WINDOWPLACEMENT replacement = new WINDOWPLACEMENT();
                    replacement.Length = Marshal.SizeOf(placement);



                    GetWindowPlacement(last_hwnd, ref replacement);

                    PostMessage(last_hwnd, 0x0112, 0xF120, 0);

                    last_hwnd = 0;

                    return;
                }

                if (placement.ShowCmd == 1) // if window is normal 
                {

                    PostMessage(GetForegroundWindow(), 0x0112, 0xF030, 0); // maximize

                }

                else
                {

                    PostMessage(GetForegroundWindow(), 0x0112, 0xF120, 0); // else it is maximized so  make it normal

                }

            }

            if (direction == 2) // if direction is downwward
            {


                last_hwnd = GetForegroundWindow();


                if (startbuttonHandle.ToInt32() == last_hwnd) // if the handle returned is the one for Start button then save the last real window handle and do nothing
                {
                    last_hwnd = acceptable_hwnd;
                    return;
                }

                else
                {
                    acceptable_hwnd = last_hwnd; //this way you create a small feedback between the Start button handle and the last real handle so as no matter how many times you swipe down, last_hwnd will remain in the last real minimized window
                    PostMessage(last_hwnd, 0x0112, 0xF020, 0);
                }

            }

        }
    }
}
